using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using RTMP.SimpleClient.Helpers;

namespace RTMP.SimpleClient.Tests.MockServer
{
    /// <summary>
    /// Mock RTMP 服务器实现
    /// </summary>
    public class RTMPMockServer : IRTMPMockServer
    {
        private TcpListener? _tcpListener;
        private TcpClient? _connectedClient;
        private NetworkStream? _clientStream;
        private CancellationTokenSource? _serverCts;
        private Task? _serverTask;

        private MockServerState _currentState = MockServerState.Stopped;
        private readonly object _stateLock = new object();
        private readonly object _clientLock = new object();

        private uint _nextStreamId = 1;
        private int _chunkSize = 128;
        private readonly ChunkProcessor _chunkProcessor = new();
        private readonly CommandProcessor _commandProcessor = new();

        /// <summary>
        /// 获取当前服务器状态
        /// </summary>
        public MockServerState CurrentState
        {
            get
            {
                lock (_stateLock)
                {
                    return _currentState;
                }
            }
        }

        /// <summary>
        /// 获取服务器监听端口
        /// </summary>
        public int Port { get; private set; }

        /// <summary>
        /// 获取服务器监听地址
        /// </summary>
        public string Host { get; private set; } = "localhost";

        /// <summary>
        /// 状态变化事件
        /// </summary>
        public event EventHandler<StateChangedEventArgs>? StateChanged;

        /// <summary>
        /// 客户端连接事件
        /// </summary>
        public event EventHandler<ClientConnectedEventArgs>? ClientConnected;

        /// <summary>
        /// 客户端断开事件
        /// </summary>
        public event EventHandler<ClientDisconnectedEventArgs>? ClientDisconnected;

        /// <summary>
        /// 命令接收事件
        /// </summary>
        public event EventHandler<CommandReceivedEventArgs>? CommandReceived;

        /// <summary>
        /// 线程安全地更改状态
        /// </summary>
        private void ChangeState(MockServerState newState)
        {
            MockServerState previousState;
            lock (_stateLock)
            {
                previousState = _currentState;
                if (previousState == newState) return;
                _currentState = newState;
            }

            StateChanged?.Invoke(this, new StateChangedEventArgs(previousState, newState));
            Console.WriteLine($"[MockServer] 状态变化: {previousState} -> {newState}");
        }

        /// <summary>
        /// 启动Mock服务器
        /// </summary>
        public async Task StartAsync(string host = "localhost", int port = 0, CancellationToken cancellationToken = default)
        {
            if (CurrentState != MockServerState.Stopped)
            {
                throw new InvalidOperationException($"服务器必须处于停止状态才能启动，当前状态: {CurrentState}");
            }

            ChangeState(MockServerState.Starting);

            try
            {
                Host = host;
                _tcpListener = new TcpListener(IPAddress.Parse(host), port);
                _tcpListener.Start();
                
                // 获取实际监听端口
                Port = ((IPEndPoint)_tcpListener.LocalEndpoint).Port;
                
                _serverCts = new CancellationTokenSource();
                
                ChangeState(MockServerState.Listening);
                Console.WriteLine($"[MockServer] 开始监听 {Host}:{Port}");

                // 启动服务器任务
                _serverTask = RunServerAsync(_serverCts.Token);
                
                await Task.CompletedTask;
            }
            catch (Exception ex)
            {
                ChangeState(MockServerState.Error);
                Console.WriteLine($"[MockServer] 启动失败: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 停止Mock服务器
        /// </summary>
        public async Task StopAsync(CancellationToken cancellationToken = default)
        {
            if (CurrentState == MockServerState.Stopped)
            {
                return;
            }

            ChangeState(MockServerState.Disconnecting);

            try
            {
                // 取消服务器任务
                _serverCts?.Cancel();

                // 等待服务器任务完成
                if (_serverTask != null)
                {
                    await _serverTask;
                }

                // 关闭客户端连接
                await DisconnectClientAsync();

                // 停止监听器
                _tcpListener?.Stop();

                ChangeState(MockServerState.Stopped);
                Console.WriteLine($"[MockServer] 服务器已停止");
            }
            catch (Exception ex)
            {
                ChangeState(MockServerState.Error);
                Console.WriteLine($"[MockServer] 停止失败: {ex.Message}");
                throw;
            }
            finally
            {
                _tcpListener = null;
                _serverTask = null;
                _serverCts?.Dispose();
                _serverCts = null;
            }
        }

        /// <summary>
        /// 等待客户端连接
        /// </summary>
        public async Task WaitForClientConnectionAsync(TimeSpan timeout = default, CancellationToken cancellationToken = default)
        {
            if (timeout == default)
                timeout = TimeSpan.FromSeconds(30);

            using var timeoutCts = new CancellationTokenSource(timeout);
            using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);

            while (CurrentState != MockServerState.ClientConnected && 
                   CurrentState != MockServerState.HandshakeInProgress && 
                   CurrentState != MockServerState.Connected &&
                   !combinedCts.Token.IsCancellationRequested)
            {
                await Task.Delay(50, combinedCts.Token);
            }

            combinedCts.Token.ThrowIfCancellationRequested();
        }

        /// <summary>
        /// 等待达到指定状态
        /// </summary>
        public async Task WaitForStateAsync(MockServerState expectedState, TimeSpan timeout = default, CancellationToken cancellationToken = default)
        {
            if (timeout == default)
                timeout = TimeSpan.FromSeconds(30);

            using var timeoutCts = new CancellationTokenSource(timeout);
            using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);

            while (CurrentState != expectedState && !combinedCts.Token.IsCancellationRequested)
            {
                await Task.Delay(50, combinedCts.Token);
            }

            combinedCts.Token.ThrowIfCancellationRequested();
        }

        /// <summary>
        /// 服务器主循环
        /// </summary>
        private async Task RunServerAsync(CancellationToken cancellationToken)
        {
            try
            {
                while (!cancellationToken.IsCancellationRequested && _tcpListener != null)
                {
                    Console.WriteLine($"[MockServer] 等待客户端连接...");
                    var tcpClient = await _tcpListener.AcceptTcpClientAsync();
                    
                    Console.WriteLine($"[MockServer] 客户端连接: {tcpClient.Client.RemoteEndPoint}");
                    
                    lock (_clientLock)
                    {
                        _connectedClient = tcpClient;
                        _clientStream = tcpClient.GetStream();
                    }

                    ChangeState(MockServerState.ClientConnected);
                    ClientConnected?.Invoke(this, new ClientConnectedEventArgs(tcpClient.Client.RemoteEndPoint?.ToString() ?? "Unknown"));

                    // 处理客户端连接
                    _ = Task.Run(async () => await HandleClientAsync(tcpClient, cancellationToken), cancellationToken);
                }
            }
            catch (ObjectDisposedException)
            {
                // TCP监听器被释放，正常情况
            }
            catch (Exception ex) when (!cancellationToken.IsCancellationRequested)
            {
                Console.WriteLine($"[MockServer] 服务器运行错误: {ex.Message}");
                ChangeState(MockServerState.Error);
            }
        }

        /// <summary>
        /// 处理单个客户端连接
        /// </summary>
        private async Task HandleClientAsync(TcpClient client, CancellationToken cancellationToken)
        {
            try
            {
                using (client)
                using (var stream = client.GetStream())
                {
                    // 开始RTMP握手处理
                    ChangeState(MockServerState.HandshakeInProgress);
                    await HandleHandshakeAsync(stream, cancellationToken);

                    ChangeState(MockServerState.Connected);
                    Console.WriteLine($"[MockServer] RTMP连接建立完成");

                    // 处理RTMP命令
                    await HandleRTMPCommandsAsync(stream, cancellationToken);
                }
            }
            catch (Exception ex) when (!cancellationToken.IsCancellationRequested)
            {
                Console.WriteLine($"[MockServer] 客户端处理错误: {ex.Message}");
                ChangeState(MockServerState.Error);
            }
            finally
            {
                await DisconnectClientAsync();
            }
        }

        /// <summary>
        /// 断开客户端连接
        /// </summary>
        private async Task DisconnectClientAsync()
        {
            lock (_clientLock)
            {
                if (_connectedClient != null)
                {
                    var endpoint = _connectedClient.Client.RemoteEndPoint?.ToString() ?? "Unknown";
                    Console.WriteLine($"[MockServer] 客户端断开: {endpoint}");
                    
                    _clientStream?.Close();
                    _connectedClient.Close();
                    
                    _clientStream = null;
                    _connectedClient = null;
                    
                    ClientDisconnected?.Invoke(this, new ClientDisconnectedEventArgs(endpoint));
                }
            }
            
            await Task.CompletedTask;
        }

        /// <summary>
        /// 处理RTMP握手
        /// </summary>
        private async Task HandleHandshakeAsync(NetworkStream stream, CancellationToken cancellationToken)
        {
            await HandshakeHandler.PerformServerHandshakeAsync(stream, cancellationToken);
        }

        /// <summary>
        /// 处理RTMP命令
        /// </summary>
        private async Task HandleRTMPCommandsAsync(NetworkStream stream, CancellationToken cancellationToken)
        {
            var buffer = new byte[4096];
            
            while (!cancellationToken.IsCancellationRequested && stream.CanRead)
            {
                try
                {
                    int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken);
                    if (bytesRead == 0)
                    {
                        Console.WriteLine($"[MockServer] 客户端关闭连接");
                        break;
                    }

                    Console.WriteLine($"[MockServer] 收到 {bytesRead} 字节数据");
                    await ProcessReceivedDataAsync(stream, buffer, bytesRead, cancellationToken);
                }
                catch (IOException ex)
                {
                    Console.WriteLine($"[MockServer] 网络IO错误: {ex.Message}");
                    break;
                }
            }
        }

        /// <summary>
        /// 处理接收到的数据
        /// </summary>
        private async Task ProcessReceivedDataAsync(NetworkStream stream, byte[] buffer, int length, CancellationToken cancellationToken)
        {
            try
            {
                // 使用chunk处理器解析数据
                var messages = _chunkProcessor.ProcessData(buffer, 0, length);

                foreach (var message in messages)
                {
                    Console.WriteLine($"[MockServer] 解析到消息: Type={message.MessageTypeId}, Length={message.MessageLength}, StreamId={message.MessageStreamId}");

                    // 如果是命令消息，使用命令处理器处理
                    if (message.MessageTypeId == 20) // AMF0 Command Message
                    {
                        await _commandProcessor.ProcessCommandAsync(message, stream, CommandReceived, cancellationToken);
                        
                        // 根据命令类型更新服务器状态
                        UpdateServerStateForCommand(message);
                    }
                    else if (message.MessageTypeId == 1) // Set Chunk Size
                    {
                        Console.WriteLine($"[MockServer] 客户端设置Chunk Size");
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[MockServer] 处理数据失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 根据命令更新服务器状态
        /// </summary>
        private void UpdateServerStateForCommand(RTMPMessage message)
        {
            try
            {
                // 简单解析命令名以确定状态变化
                if (message.Data.Length > 10)
                {
                    string dataStr = System.Text.Encoding.UTF8.GetString(message.Data, 0, Math.Min(100, message.Data.Length));
                    
                    if (dataStr.Contains("connect"))
                    {
                        // Connect命令不改变状态，保持Connected
                    }
                    else if (dataStr.Contains("createStream"))
                    {
                        // CreateStream命令不改变状态，保持Connected
                    }
                    else if (dataStr.Contains("play") || dataStr.Contains("publish"))
                    {
                        ChangeState(MockServerState.Streaming);
                    }
                }
            }
            catch
            {
                // 忽略解析错误
            }
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            try
            {
                StopAsync().GetAwaiter().GetResult();
            }
            catch
            {
                // 忽略停止时的错误
            }
        }
    }
}